package br.unifor.cct.mia.evaluate;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import br.unifor.cct.mia.dataenhancement.Structure;
import br.unifor.cct.mia.dataenhancement.Tuple;
import br.unifor.cct.mia.evaluate.classification.WekaClassification;
import br.unifor.cct.mia.evolutionary.Genotype;
import br.unifor.cct.mia.ga.Ga;
import br.unifor.cct.mia.util.Methods;
import br.unifor.cct.mia.util.SaveReport;

public class Weka implements Evaluate {
	
	private List positions;
	private Structure structure;
	private Map genesAnt;
	private Tuple tuples;
	private Ga ga;
	private String[] options;
	
	public double cost(Genotype gen) {		
		double sum = 0;
		
		Double hashCode = generateHashCode(gen);
		if (!genesAnt.containsKey(hashCode)) {			

			try {
				SaveReport report = new SaveReport("temp/result.txt",structure.getStrucFile());
				//report.addLine(tuples.string(structure.getStringValues(positions, gen.getGene())));
				report.addLine(tuples.stringWithValues(positions, gen.getGene(), structure));
				report.saveToDisk();
				
				WekaClassification classificator = new WekaClassification(ga.getLearnerType(),options);
				sum = classificator.evaluate(report.getFile());				
			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
			
			genesAnt.put(hashCode, new Double(sum));
		}
		else {
			sum = ((Double)genesAnt.get(hashCode)).doubleValue();
		}
		
		return sum;
	}

	public Object evaluate(Object value,String[] options) {
		this.options = options;
		Object[] o = (Object[]) value;
		positions = (List)o[0];
		structure = (Structure)o[1];
		genesAnt = (Map) o[2];
		tuples = (Tuple) o[3];
		ga = (Ga)o[4];
		
		ga.sum = 0;
		ga.indexBestWorst[0] = ga.indexBestWorst[1] = 0;
       
        for(int i = 0; i < ga.configurations.getPopsize(); i++) {        	
        	ga.population[i].setFitness(cost((Genotype)ga.population[i]));                    	
            if (ga.population[i].getFitness() > ga.population[ga.indexBestWorst[0]].getFitness()) 
            	ga.indexBestWorst[0] = i;
            else 
            	if (ga.population[i].getFitness() < ga.population[ga.indexBestWorst[1]].getFitness()) 
            		ga.indexBestWorst[1] = i;
            	
            ga.sum += ga.population[i].getFitness();
        }
        
		return ga.population;
	}
	
	public double generateHashCode(Genotype gen) {
		double[] gene = gen.getGene();
		double hashCode = 0;
		int atual = 3;
		for ( int i=0; i<gene.length; i++ ) {
			hashCode += gene[i]/Methods.gerarPrimo(atual);
			atual++;
		}		
		return hashCode;
	}
}
